﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports System.Data.Entity
Imports System.Globalization
Imports Microsoft.Samples.WindowsPhoneCloud.Web.Controllers
Imports Microsoft.Samples.WindowsPhoneCloud.Web.Infrastructure
Imports Microsoft.Samples.WindowsPhoneCloud.Web.Services
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.ServiceRuntime

Public Class MvcApplication
    Inherits System.Web.HttpApplication
    Private Const DefaultHttpsPort As Integer = 443
    Private Const DefaultHttpPort As Integer = 10080
    Private Const PortErrorMessage As String = "The Web role was started in a wrong port." & ControlChars.CrLf & "                                            For this sample application to work correctly, please make sure that it is running in port {0}. " & ControlChars.CrLf & "                                            Please review the Troubleshooting section of the sample documentation for instructions on how to do this."

    Private Shared securityInitialized As Boolean = False
    Public Shared Sub RegisterGlobalFilters(ByVal filters As GlobalFilterCollection)
        filters.Add(New HandleErrorAttribute())
    End Sub

    Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

        routes.MapRoute("Default", "{controller}/{action}/{id}", New With {Key .controller = "Home", Key .action = "Index", Key .id = CStr(Nothing)}, New With {Key .controller = New ListConstraint(ListConstraintType.Exclude, "AuthenticationService", "PushNotificationService", "SqlAzureSampleODataService")})
    End Sub

    Protected Sub Application_Start()
        AreaRegistration.RegisterAllAreas()

        RegisterGlobalFilters(GlobalFilters.Filters)
        RegisterRoutes(RouteTable.Routes)

        RouteTable.Routes.AddWcfServiceRoute(Of AuthenticationService)("AuthenticationService")
        RouteTable.Routes.AddWcfServiceRoute(Of SamplePushUserRegistrationService)("PushNotificationService")
        RouteTable.Routes.AddWcfServiceRoute(Of SqlAzureSampleODataService)("SqlAzureSampleODataService")

        ' This code initializes the database using EF 4.1 Code-First, and creates all the database objects required by the ASP.NET Membership Provider for SQL Server.
        Database.SetInitializer(Of SqlDataContext)(New SqlSampleDataInitializer())
        Dim context = New SqlDataContext()
        Dim firstItem = context.SqlSampleData.FirstOrDefault()
    End Sub

    Protected Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        If Not securityInitialized Then
            InitializeSecurity()
            securityInitialized = True
        End If
    End Sub

    Protected Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        If Me.ShouldRedirectToHttps() Then
            Me.RedirectScheme(Me.Context.Request.Url, "https")
        ElseIf Me.ShouldRedirectToHttp() Then
            Me.RedirectScheme(Me.Context.Request.Url, "http")
        End If

        If (Not Me.IsPortNumberOK()) AndAlso (Not IsAllowedContent(Me.Context.Request.Path)) Then
            Me.CreateWrongPortException()
        End If
    End Sub

    Private Shared Sub InitializeSecurity()
        Dim adminUser = Membership.FindUsersByName("admin").Cast(Of MembershipUser)().FirstOrDefault()
        If adminUser Is Nothing Then
            adminUser = Membership.CreateUser("admin", "Passw0rd!", "admin@wp7cloudapp.com")
        End If

        Dim adminUserId = adminUser.ProviderUserKey.ToString()
        Dim userPrivilegesRepository As IUserPrivilegesRepository = New SqlDataContext()
        userPrivilegesRepository.AddPrivilegeToUser(adminUserId, PrivilegeConstants.AdminPrivilege)
        userPrivilegesRepository.AddPrivilegeToUser(adminUserId, PrivilegeConstants.SqlUsagePrivilege)
    End Sub

    Private Shared Function IsAllowedContent(ByVal path As String) As Boolean
        Return path.EndsWith("/Error", StringComparison.OrdinalIgnoreCase) OrElse path.StartsWith("/Content", StringComparison.OrdinalIgnoreCase) OrElse path.StartsWith("/Scripts", StringComparison.OrdinalIgnoreCase)
    End Function

    Private Sub RedirectScheme(ByVal originalUri As Uri, ByVal intendedScheme As String)
        Dim portNumber As Integer = 0
        If intendedScheme.Equals("https", StringComparison.OrdinalIgnoreCase) Then
            portNumber = DefaultHttpsPort
        ElseIf intendedScheme.Equals("http", StringComparison.OrdinalIgnoreCase) Then
            portNumber = DefaultHttpPort
        End If

        Dim redirectUrl = String.Format(CultureInfo.InvariantCulture, "{0}://{1}:{2}{3}", intendedScheme, originalUri.Host, portNumber, originalUri.PathAndQuery)

        Me.Response.Redirect(redirectUrl, True)
    End Sub

    Private Function ShouldRedirectToHttp() As Boolean
        Return Me.Request.IsSecureConnection AndAlso Me.Context.Request.Url.ToString().EndsWith(".cer", StringComparison.OrdinalIgnoreCase)
    End Function

    Private Function ShouldRedirectToHttps() As Boolean
        Return (Not Me.Request.IsSecureConnection) AndAlso Not Me.Context.Request.Url.ToString().EndsWith(".cer", StringComparison.OrdinalIgnoreCase)
    End Function

    Private Sub CreateWrongPortException()
        Dim exception = New RoleInWrongPortException(String.Format(CultureInfo.InvariantCulture, PortErrorMessage, DefaultHttpsPort))
        Dim routeData = New RouteData()
        routeData.Values.Add("Controller", "Error")
        routeData.Values.Add("Action", "Index")
        routeData.Values.Add("Error", exception)

        Using errorController = New ErrorController()
            CType(errorController, IController).Execute(New RequestContext(New HttpContextWrapper(Me.Context), routeData))
        End Using

        Me.Context.Response.End()
    End Sub

    Private Function IsPortNumberOK() As Boolean
        Dim scheme = Me.Context.Request.Url.Scheme
        Dim portNumber = 0

        If scheme.Equals("https") Then
            portNumber = DefaultHttpsPort
        ElseIf scheme.Equals("http") Then
            portNumber = DefaultHttpPort
        End If

        Dim hostAddress = If(Me.Context.Request.Headers("Host"), String.Empty)
        Dim portPosition = hostAddress.IndexOf(":", StringComparison.OrdinalIgnoreCase)

        If portPosition > 0 Then
            Integer.TryParse(hostAddress.Substring(portPosition + 1), portNumber)
        End If

        Return (portNumber = DefaultHttpsPort) OrElse ((portNumber = DefaultHttpPort) AndAlso Context.Request.Url.ToString().EndsWith(".cer", StringComparison.OrdinalIgnoreCase))
    End Function
End Class
